﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Text;
using Athena.Core;

namespace Athena.Objects
{
    [Serializable()]
    public class MultimericSpecies : ContainerGlyph
    {
        public override object Clone()
        {
            return new MultimericSpecies(this);
        }

        public MultimericSpecies(MultimericSpecies copy)
            : base(copy)
        {
            _oShape = copy.Shape;
            _RespondsToCollision = true;
            if (copy.Item is Species)
                Item = copy.Item.Clone() as Species;
        }


        /// <summary>
        /// The complete constructor of a Compartment
        /// </summary>
        /// <param name="location"></param>
        public MultimericSpecies(PointF location, SizeF dimension, List<IDrawable> nodes, List<Connector> edges, List<IDrawable> inputs, List<IDrawable> outputs)
        {
            _oShape = SHAPE.Octahedron;
            TextH = HorizontalAlignment.Center;
            TextV = VerticalAlignment.Top;

            _Location = location;
            _Dimensions = dimension;
            Name = "Module_" + Compartment.COUNT;
            _oFillColorStart = Color.White;
            _oFillColorEnd = Color.White;
            _oEdgeColor = Color.SteelBlue;
            _RespondsToCollision = true;
            _Drawables = nodes;

            Item = new Species("species", "complex", false, 0);
        }

        /// <summary>
        /// Initializes a new instance of the PartGlyph class.
        /// </summary>
        /// <param name="location"></param>
        public MultimericSpecies(PointF location)
            : base(location)
        {
            _oShape = SHAPE.Octahedron;
            TextH = HorizontalAlignment.Center;
            TextV = VerticalAlignment.BelowBottom;
            _oFillColorStart = Color.White;
            _oFillColorEnd = Color.White;
            _oEdgeColor = Color.SteelBlue;
            _RespondsToCollision = true;
            Item = new Species("complex", "Complex_0", false, 0);
        }

        public MultimericSpecies()
            : base()
        {
            _oShape = SHAPE.Octahedron;
            _oFillColorStart = Color.White;
            _oFillColorEnd = Color.White;
            _oEdgeColor = Color.SteelBlue;
            _RespondsToCollision = true;
            Item = new Species("complex", "Complex_0", false, 0);
        }

        public override bool HasPreview
        {
            get { return true; }
        }

        public override void AddItem(IDrawable drawable, bool adjustSize)
        {
            if (drawable == null || _Drawables.Contains(drawable)) return;
            if (_AnchoredItems != null && _AnchoredItems.Contains(drawable)) return;

            if (!drawable.NullItem)
            {
                //drawable.Location = new PointF(drawable.Location.X - 5, drawable.Location.Y - 5);
                IDrawable alias = drawable.GenerateAlias();
                _Drawables.Add(alias);
                alias.Parent = this;

                Program.Model.Drawables.Add(alias);
                drawable.UndoMove();

                //drawable.Location = new PointF(drawable.Location.X + 10, drawable.Location.Y + 10);
            }
            else
            {
                _Drawables.Add(drawable);
                drawable.Parent = this;
            }
            //Utility.BringItemToFront(drawable, Program.Model);
            Utility.MoveBehindOf(this, drawable, Program.Model);
            Utility.Refresh();
        }

        public override bool ChildChanged(IDrawable child)
        {
            if (!(child.Item == null || child.NullItem))
                _Drawables.Remove(child);

            return base.ChildChanged(child);
        }

        public override void HitBy(ICollection<IDrawable> drawables, bool moving)
        {
            base.HitBy(drawables, moving);
            foreach (IDrawable drawable in drawables)
            {
                if (drawable is Connector)
                {
                    Connector c = (Connector)drawable;
                    if (c.AnchoredSource != null)
                    {
                        c.AnchoredSource = null;
                    }
                    /*foreach (IDrawable id in _Drawables)
                    {
                        if (c.Inputs.Contains(id) || c.Outputs.Contains(id))
                            c.SubstituteNode(id, this);
                    }*/
                }
            }
        }

        public override void HitBy(IDrawable drawable, bool moving)
        {
            base.HitBy(drawable, moving);
            if (drawable is Connector)
            {
                Connector c = (Connector)drawable;
                if (c.AnchoredSource != null)
                {
                    c.AnchoredSource = null;
                }
                /*foreach (IDrawable id in _Drawables)
                {
                    if (c.Inputs.Contains(id) || c.Outputs.Contains(id))
                        c.SubstituteNode(id, this);
                }*/
            }
        }

        /// <summary>
        /// render the compartment
        /// </summary>
        /// <param name="g"></param>
        public override void RenderGlyph(Graphics g)
        {
            Pen oOutline = new Pen(_oEdgeColor, _dEdgeThickness);

            RectangleF oTemp = Bounds;

            Brush oFilled;
            if (_oFillColorStart == _oFillColorEnd || _Dimensions.Width < 2 || _Dimensions.Height < 2)
                oFilled = new SolidBrush(_oFillColorStart);
            else
                oFilled = new LinearGradientBrush(Location, new PointF(Location.X + Dimensions.Width, Location.Y + Dimensions.Height), _oFillColorStart, _oFillColorEnd);

            Pen glow = new Pen(Color.OrangeRed, 5);
            GraphicsPath path = new GraphicsPath();

            switch (Shape)
            {
                case SHAPE.Box:
                    {
                        g.FillRectangle(oFilled, oTemp);
                        oTemp.Inflate(-_dEdgeThickness, -_dEdgeThickness);
                        g.DrawRectangle(oOutline, oTemp.X, oTemp.Y, oTemp.Width, oTemp.Height);
                        if (_Glow)
                        {
                            oTemp.Inflate(2 * _dEdgeThickness, 2 * _dEdgeThickness);
                            g.DrawRectangle(glow, oTemp.X, oTemp.Y, oTemp.Width, oTemp.Height);
                        }
                        break;
                    }
                case SHAPE.Ellipse:
                    {
                        g.FillEllipse(oFilled, oTemp.X, oTemp.Y, oTemp.Width, oTemp.Height);
                        oTemp.Inflate(-_dEdgeThickness, -_dEdgeThickness);
                        g.DrawEllipse(oOutline, oTemp.X, oTemp.Y, oTemp.Width, oTemp.Height);
                        if (_Glow)
                        {
                            oTemp.Inflate(2 * _dEdgeThickness, 2 * _dEdgeThickness);
                            g.DrawEllipse(glow, oTemp.X, oTemp.Y, oTemp.Width, oTemp.Height);
                        }
                        break;
                    }
                case SHAPE.Octahedron:
                    {
                        float dOffset = Math.Min(Bounds.Width, Bounds.Height) * 0.10f;

                        GraphicsPath oPath = new GraphicsPath();

                        oPath.AddLine(oTemp.X, oTemp.Y + dOffset,
                                      oTemp.X + dOffset, oTemp.Y);
                        oPath.AddLine(oTemp.X + dOffset, oTemp.Y,
                                      oTemp.X + oTemp.Width - dOffset, oTemp.Y);
                        oPath.AddLine(oTemp.X + oTemp.Width - dOffset, oTemp.Y,
                                      oTemp.X + oTemp.Width, oTemp.Y + dOffset);
                        oPath.AddLine(oTemp.X + oTemp.Width, oTemp.Y + dOffset,
                                      oTemp.X + oTemp.Width, oTemp.Y + oTemp.Height - dOffset);
                        oPath.AddLine(oTemp.X + oTemp.Width, oTemp.Y + oTemp.Height - dOffset,
                                      oTemp.X + oTemp.Width - dOffset, oTemp.Y + oTemp.Height);
                        oPath.AddLine(oTemp.X + oTemp.Width - dOffset, oTemp.Y + oTemp.Height,
                                      oTemp.X + dOffset, oTemp.Y + oTemp.Height);
                        oPath.AddLine(oTemp.X + dOffset, oTemp.Y + oTemp.Height,
                                      oTemp.X, oTemp.Y + oTemp.Height - dOffset);
                        oPath.AddLine(oTemp.X, oTemp.Y + oTemp.Height - dOffset,
                                      oTemp.X, oTemp.Y + dOffset);

                        oPath.CloseFigure();
                        g.FillPath(oFilled, oPath);

                        if (ShowCloneMarker)
                        {

                            LinearGradientBrush oBrush = new LinearGradientBrush(Bounds, Color.Transparent, CloneMarkerColor, LinearGradientMode.Vertical);
                            ColorBlend oBlend = new ColorBlend(2);
                            oBlend.Positions = new float[] { 0f, 1f - ClonePercentage, 1f - ClonePercentage, 1f };
                            oBlend.Colors = new Color[] { Color.Transparent, Color.Transparent, CloneMarkerColor, CloneMarkerColor };
                            oBrush.InterpolationColors = oBlend;
                            g.FillPath(oBrush, oPath);
                            DrawCloneMarkerText(g);
                        }


                        g.DrawPath(oOutline, oPath);

                        if (_Glow)
                        {
                            GraphicsPath oPath2 = new GraphicsPath();

                            oPath2.AddLine(oTemp.X, oTemp.Y + dOffset,
                                          oTemp.X + dOffset, oTemp.Y);
                            oPath2.AddLine(oTemp.X + dOffset, oTemp.Y,
                                          oTemp.X + oTemp.Width - dOffset, oTemp.Y);
                            oPath2.AddLine(oTemp.X + oTemp.Width - dOffset, oTemp.Y,
                                          oTemp.X + oTemp.Width, oTemp.Y + dOffset);
                            oPath2.AddLine(oTemp.X + oTemp.Width, oTemp.Y + dOffset,
                                          oTemp.X + oTemp.Width, oTemp.Y + oTemp.Height - dOffset);
                            oPath2.AddLine(oTemp.X + oTemp.Width, oTemp.Y + oTemp.Height - dOffset,
                                          oTemp.X + oTemp.Width - dOffset, oTemp.Y + oTemp.Height);
                            oPath2.AddLine(oTemp.X + oTemp.Width - dOffset, oTemp.Y + oTemp.Height,
                                          oTemp.X + dOffset, oTemp.Y + oTemp.Height);
                            oPath2.AddLine(oTemp.X + dOffset, oTemp.Y + oTemp.Height,
                                          oTemp.X, oTemp.Y + oTemp.Height - dOffset);
                            oPath2.AddLine(oTemp.X, oTemp.Y + oTemp.Height - dOffset,
                                          oTemp.X, oTemp.Y + dOffset);

                            oPath2.CloseFigure();
                            //g.FillPath(oFilled, oPath2);
                            g.DrawPath(new Pen(Color.OrangeRed, 3), oPath2);
                        }

                        break;
                    }
                case SHAPE.RoundedRectangle:
                    {
                        GraphicsPath oPath = new GraphicsPath();

                        Utility.GenerateRoundedRectangle(oPath, oTemp);
                        RectangleF pathBounds = oPath.GetBounds();
                        Matrix oTransform = new Matrix();

                        oTransform.Scale(
                            oTemp.Width / pathBounds.Width,
                            oTemp.Height / pathBounds.Height, MatrixOrder.Prepend);
                        oTransform.Translate(oTemp.X - pathBounds.X * oTemp.Width / pathBounds.Width, oTemp.Y - pathBounds.Y * oTemp.Height / pathBounds.Height, MatrixOrder.Append);

                        oPath.Transform(oTransform);

                        path.AddPath(oPath, false);

                        g.FillPath(oFilled, path);

                        g.DrawPath(oOutline, path);

                        if (_Glow)
                        {
                            g.DrawPath(glow, oPath);
                        }

                        break;
                    }
            }

        }

        public override void ShowToolTip(ToolTip tooltip, Control pnlCanvas, PointF location)
        {
            tooltip.ToolTipTitle = "Complex species: ";
            tooltip.SetToolTip(pnlCanvas,
                String.Format(
                            "{2}ID:\t{0}"
                          + "{2}Num. monomers:\t{1}",
                Name,
                _Drawables.Count,
                "\r\n"));
        }
    }
}
